package com.lanhao.aot.aes;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * @author wangqian
 * @date 17/11/21 下午2:30
 * <p>
 * AES对称加密工具类
 */
public class AESCryptUtils {

    private static final String IV_PARAMETER = "176d3805f01deeab";
    // 编码方式
    private static final String CHARSET_NAME = "UTF-8";

    private static final String KEY_ALGORITHM = "AES";

    private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";

    private static final String CIPHER_ALGORITHM_ECB = "AES/ECB/PKCS5Padding";

    /**
     * 加密
     *
     * @param data 加密内容
     * @param key  原始密钥
     * @param iv   16bytes初始向量
     * @return
     */
    public static String encode(String data, String key, String iv) {
        return encrypt(data, key, iv);
    }

    public static String encode(String data, String key) {
        return encrypt(data, md5Hex16(key), IV_PARAMETER);
    }

    /**
     * 解密
     *
     * @param data 解密内容
     * @param key  原始密钥
     * @param iv   16bytes初始向量
     * @return
     */
    public static String decode(String data, String key, String iv) {
        return decrypt(data, key, iv);
    }

    public static String decode(String data, String key) {
        return decrypt(data, md5Hex16(key), IV_PARAMETER);
    }

    /**
     * 16位md5加密
     *
     * @param key 原始密钥
     * @return
     */
    public static String md5Hex16(String key) {
        return DigestUtils.md5Hex(key.getBytes()).substring(8, 24);
    }

    /**
     * 加密
     *
     * @param data   加密内容
     * @param md5Key 16位md5后的密钥
     * @param iv     初始向量
     * @return
     */
    private static String encrypt(String data, String md5Key, String iv) {
        try {
            IvParameterSpec zeroIv = new IvParameterSpec(iv.getBytes());
            // 两个参数，第一个为私钥字节数组， 第二个为加密方式 AES或者DES
            SecretKeySpec key = new SecretKeySpec(md5Key.getBytes(), KEY_ALGORITHM);
            // 实例化加密类，参数为加密方式，要写全
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            // 初始化，此方法可以采用三种方式，按加密算法要求来添加。（1）无第三个参数（2）第三个参数为SecureRandom random = new
            // SecureRandom();中random对象，随机数。(AES不可采用这种方法)（3）采用此代码中的IVParameterSpec
            cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
            // 加密操作,返回加密后的字节数组，然后需要编码。主要编解码方式有Base64, HEX, UUE,7bit等等。此处看服务器需要什么编码方式
            byte[] encryptedData = cipher.doFinal(data.getBytes(CHARSET_NAME));
            return Base64.encodeBase64String(encryptedData); // 用此方法不带换行符的

        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 解密
     *
     * @param data   解密内容
     * @param strKey 16位密钥
     * @param iv     初始向量
     * @return
     */
    private static String decrypt(String data, String strKey, String iv) {
        try {
            byte[] byteMi = Base64.decodeBase64(data);
            IvParameterSpec zeroIv = new IvParameterSpec(iv.getBytes());
            SecretKeySpec key = new SecretKeySpec(strKey.getBytes(), KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            // 与加密时不同MODE:Cipher.DECRYPT_MODE
            cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
            byte[] decryptedData = cipher.doFinal(byteMi);
            return new String(decryptedData, CHARSET_NAME);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /***************** ECB部分 ***************************/

    public static String encodeECB(String data, String key) {
        return encryptECB(data, key);
    }

    /**
     * 加密
     *
     * @param data   加密内容
     * @param md5Key 16位md5后的密钥
     * @param iv     初始向量
     * @return
     */
    public static String encryptECB(String data, String md5Key) {
        try {
            // 两个参数，第一个为私钥字节数组， 第二个为加密方式 AES或者DES
            SecretKeySpec key = new SecretKeySpec(md5Key.getBytes(), KEY_ALGORITHM);
            // 实例化加密类，参数为加密方式，要写全
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB);
            // 初始化，此方法可以采用三种方式，按加密算法要求来添加。（1）无第三个参数（2）第三个参数为SecureRandom random = new
            // SecureRandom();中random对象，随机数。(AES不可采用这种方法)（3）采用此代码中的IVParameterSpec
            cipher.init(Cipher.ENCRYPT_MODE, key);
            // 加密操作,返回加密后的字节数组，然后需要编码。主要编解码方式有Base64, HEX, UUE,7bit等等。此处看服务器需要什么编码方式
            byte[] encryptedData = cipher.doFinal(data.getBytes(CHARSET_NAME));
            return Base64.encodeBase64String(encryptedData); // 用此方法不带换行符的

        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    public static String decodeECB(String data, String key) {
        return decryptECB(data, key);
    }

    /**
     * 解密
     *
     * @param data   解密内容
     * @param strKey 16位密钥
     * @param iv     初始向量
     * @return
     */
    public static String decryptECB(String data, String strKey) {
        try {
            byte[] byteMi = Base64.decodeBase64(data);
            SecretKeySpec key = new SecretKeySpec(strKey.getBytes(), KEY_ALGORITHM);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM_ECB);
            // 与加密时不同MODE:Cipher.DECRYPT_MODE
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decryptedData = cipher.doFinal(byteMi);
            return new String(decryptedData, CHARSET_NAME);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 测试
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        /*
         * //初始向量,AES为16bytes String IV_PARAMETER = "176d3805f01deeab"; String content =
         * "使用AES对称加密"; String key = "test"; //md5密钥 System.out.println("16位md5密钥：" +
         * md5Hex16(key)); //偏移量 System.out.println("初始向量：" + IV_PARAMETER); // 加密
         * System.out.println("加密前：" + content); String encryptResult =
         * "XstGJfqZ8iufC5YfViAsOx/HaMSSZdeJtZTuSDQwAR+GWt38645rk6JF0WAHnsUQGfoQt6wijJ45e4fFVpFUOjUR/QjfYuds0r3stDRmFPQ2bIVOKShjGPfP7Ucoj4MGIACheYRG9iK0Vs0M3KRFiyIDk/pCx/gMk+YoizXhRR4=";
         *
         * System.out.println("加密后：" + new String(encryptResult)); // 解密 String
         * decryptResult = decode(encryptResult, "8418123812082191",
         * "80394775195'58821"); System.out.println("解密后：" + new String(decryptResult));
         */// 181234561234777
        // String data =
        // 12:05:30\",\"rptType\":\"1\"}";
        String data1 = "{\"imei\":\"863175048608513\",\"ip\":\"192.168.0.1\",\"linkType\":\"1\",\"fmwVersion\":\"11.2.5(15D55)\",\"date\":\"2018-07-01 12:05:30\",\"rptType\":\"1\",\"timeStamp\":\"1234567890123\"}";
        String data2 = "xqaZsRaU/uH1T5JdXmcqysKxmLDVbNZqlDu7kv49FwFhamuRy3pf+24LurEmeiLa9oxyFKYG99IbcPGW5Kz6bisIL3/8xcg3QE+zyBdRtXo=";
        String pin = "9a79c9879f1a454786edc59007595e7f";
//        System.out.println(pin.length());
//        String decode1 = AESCryptUtils.decode(data2, pin.substring(0, 16), pin.substring(pin.length()-16, pin.length()-1));
//        System.out.println(decode1);
        /*String manufacturer = "B001";
		String version = "1.0";
		String encode = AESCryptUtils.encodeECB(data1, AESCryptUtils.md5Hex16(manufacturer + version));
		System.out.println("加密：" + encode);
		String decode = AESCryptUtils.decodeECB(encode, AESCryptUtils.md5Hex16(manufacturer + version));
		System.out.println("解密：" + decode);
		System.out.println(System.currentTimeMillis());*/

        String loginData = "{\"code\":\"login_req\",\"deviceId\":\"MCXF161001563455\"}";
        String pin1 = "adca4956f97f40b2a147b1227ec9c641";
        System.out.println("adca4956f97f40b2a147b1227ec9c641".length());
        String loginEn = encryptECB(loginData, pin1);
        System.out.println("logDataEn=" + loginEn);

        System.out.println("logDataDe=" + decryptECB(loginEn, pin1));


    }

}
